package com.evan.review.anr;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.evan.review.R;

import java.util.ArrayList;
import java.util.List;

/**
 * 内存紧张ANR示例Activity
 * 演示由于大量内存分配和GC导致的ANR
 */
public class LowMemoryActivity extends AppCompatActivity {

    private static final String TAG = "LowMemoryANR";

    private Button btnAllocBitmaps; // 分配位图按钮
    private Button btnClearMemory; // 清理内存按钮
    private ProgressBar progressBar; // 进度条
    private TextView tvMemoryUsage; // 内存使用量文本框
    private TextView tvLogger; // 日志文本框
    private ScrollView svLogger; // 日志滚动视图

    private List<Bitmap> bitmaps = new ArrayList<>(); // 存储位图的列表
    private final Handler handler = new Handler(Looper.getMainLooper()); // 主线程Handler
    private boolean isAllocating = false; // 是否正在分配内存
    private int currentAllocationMB = 0; // 当前已分配内存
    private final int BITMAP_SIZE = 1024; // 位图尺寸

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_low_memory);

        initViews(); // 初始化视图
        setListeners(); // 设置监听器

        logMessage("提示：点击'分配大量位图'按钮将持续分配内存，直到系统内存紧张并可能引发ANR");
        logMessage("由于内存紧张导致的ANR通常表现为频繁GC，主线程被迫等待GC完成");
        updateMemoryInfo();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        clearMemory(); // 清理内存，防止内存泄漏
    }

    /**
     * 初始化视图组件
     */
    private void initViews() {
        btnAllocBitmaps = findViewById(R.id.btn_alloc_bitmaps);
        btnClearMemory = findViewById(R.id.btn_clear_memory);
        progressBar = findViewById(R.id.progress_bar);
        tvMemoryUsage = findViewById(R.id.tv_memory_usage);
        tvLogger = findViewById(R.id.tv_logger);
        svLogger = findViewById(R.id.sv_logger);
    }

    /**
     * 设置监听器
     */
    private void setListeners() {
        btnAllocBitmaps.setOnClickListener(v -> {
            if (isAllocating) {
                stopAllocation();
            } else {
                startAllocation();
            }
        });

        btnClearMemory.setOnClickListener(v -> {
            clearMemory();
            updateMemoryInfo();
            logMessage("内存已清理");
        });
    }

    /**
     * 开始分配大量内存
     */
    private void startAllocation() {
        isAllocating = true;
        btnAllocBitmaps.setText("停止分配");
        logMessage("开始分配大量位图...");

        currentAllocationMB = 0;
        progressBar.setProgress(0);

        // 启动内存分配线程
        new Thread(() -> {
            while (isAllocating) {
                try {
                    // 在主线程分配内存，增加GC阻塞主线程的概率
                    runOnUiThread(() -> {
                        try {
                            // 创建一个大位图并添加到列表中
                            Bitmap bitmap = Bitmap.createBitmap(BITMAP_SIZE, BITMAP_SIZE, Bitmap.Config.ARGB_8888);
                            // 在位图上绘制一些内容，确保实际分配内存
                            Canvas canvas = new Canvas(bitmap);
                            canvas.drawColor(0xFFFF0000); // 填充红色

                            bitmaps.add(bitmap);

                            // 更新已分配内存量（近似值）
                            // 每个像素4字节(ARGB_8888)
                            currentAllocationMB += (BITMAP_SIZE * BITMAP_SIZE * 4) / (1024 * 1024);

                            updateMemoryInfo();

                            // 当分配到500MB左右，可能会引发较为明显的GC问题
                            if (currentAllocationMB >= 500) {
                                logMessage("已分配约500MB内存，可能会开始观察到卡顿和ANR");
                            }
                        } catch (OutOfMemoryError e) {
                            logMessage("内存溢出错误: " + e.getMessage());
                            stopAllocation();
                        }
                    });

                    // 暂停一小段时间，避免过快分配导致立即崩溃
                    Thread.sleep(50);

                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }).start();

        // 启动UI更新线程
        new Thread(() -> {
            while (isAllocating) {
                try {
                    // 更新UI显示，此处可能会因为主线程GC而延迟
                    runOnUiThread(this::updateMemoryInfo);

                    // 每秒更新一次
                    Thread.sleep(1000);

                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }).start();
    }

    /**
     * 停止内存分配
     */
    private void stopAllocation() {
        isAllocating = false;
        btnAllocBitmaps.setText("分配大量位图");
        logMessage("停止分配位图");
    }

    /**
     * 清理已分配的内存
     */
    private void clearMemory() {
        stopAllocation();

        // 释放所有位图
        for (Bitmap bitmap : bitmaps) {
            if (bitmap != null && !bitmap.isRecycled()) {
                bitmap.recycle();
            }
        }

        bitmaps.clear();
        currentAllocationMB = 0;
        progressBar.setProgress(0);

        // 建议系统执行GC
        System.gc();
    }

    /**
     * 更新内存信息显示
     */
    private void updateMemoryInfo() {
        // 获取应用可用内存信息
        Runtime runtime = Runtime.getRuntime();
        long maxMemory = runtime.maxMemory() / (1024 * 1024); // 最大内存，单位MB
        long totalMemory = runtime.totalMemory() / (1024 * 1024); // 已分配内存，单位MB
        long freeMemory = runtime.freeMemory() / (1024 * 1024); // 已分配但未使用内存，单位MB
        long usedMemory = totalMemory - freeMemory; // 已使用内存，单位MB

        String memoryInfo = String.format(
                "应用内存使用情况:\n" +
                        "最大可用内存: %d MB\n" +
                        "已使用内存: %d MB\n" +
                        "本次分配: %d MB",
                maxMemory, usedMemory, currentAllocationMB
        );

        tvMemoryUsage.setText(memoryInfo);

        // 更新进度条
        int progress = (int) ((float) usedMemory / maxMemory * 100);
        progressBar.setProgress(progress);

        // 检查内存使用是否接近上限
        if (usedMemory > maxMemory * 0.8) {
            logMessage("警告：内存使用率超过80%，即将发生频繁GC");
        }
    }

    /**
     * 记录日志信息到界面
     */
    private void logMessage(String message) {
        Log.d(TAG, message);

        handler.post(() -> {
            String currentText = tvLogger.getText().toString();
            String newText = currentText + "\n" + message;
            tvLogger.setText(newText);

            // 滚动到底部
            svLogger.post(() -> svLogger.fullScroll(View.FOCUS_DOWN));
        });
    }
} 